| Conditions | 2 |
| Paths | > 20000 |
| Total Lines | 525 |
| Code Lines | 363 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | // ---------------------------------------------------------------------------- |
||
| 28 | $.fn.markItUp = function(settings, extraSettings) { |
||
| 29 | var options, ctrlKey, shiftKey, altKey; |
||
| 30 | ctrlKey = shiftKey = altKey = false; |
||
| 31 | |||
| 32 | options = { id: '', |
||
| 33 | nameSpace: '', |
||
| 34 | root: '', |
||
| 35 | previewInWindow: '', // 'width=800, height=600, resizable=yes, scrollbars=yes' |
||
| 36 | previewAutoRefresh: true, |
||
| 37 | previewPosition: 'after', |
||
| 38 | previewTemplatePath: '~/templates/preview.html', |
||
| 39 | previewParserPath: '', |
||
| 40 | previewParserVar: 'data', |
||
| 41 | resizeHandle: true, |
||
| 42 | beforeInsert: '', |
||
| 43 | afterInsert: '', |
||
| 44 | onEnter: {}, |
||
| 45 | onShiftEnter: {}, |
||
| 46 | onCtrlEnter: {}, |
||
| 47 | onTab: {}, |
||
| 48 | markupSet: [ { /* set */ } ] |
||
| 49 | }; |
||
| 50 | $.extend(options, settings, extraSettings); |
||
| 51 | |||
| 52 | // compute markItUp! path |
||
| 53 | if (!options.root) { |
||
| 54 | $('script').each(function(a, tag) { |
||
| 55 | miuScript = $(tag).get(0).src.match(/(.*)jquery\.markitup(\.pack)?\.js/); |
||
|
|
|||
| 56 | if (miuScript !== null) { |
||
| 57 | options.root = miuScript[1]; |
||
| 58 | } |
||
| 59 | }); |
||
| 60 | } |
||
| 61 | |||
| 62 | return this.each(function() { |
||
| 63 | var $$, textarea, levels, scrollPosition, caretPosition, caretOffset, |
||
| 64 | clicked, hash, header, footer, previewWindow, template, iFrame, abort; |
||
| 65 | $$ = $(this); |
||
| 66 | textarea = this; |
||
| 67 | levels = []; |
||
| 68 | abort = false; |
||
| 69 | scrollPosition = caretPosition = 0; |
||
| 70 | caretOffset = -1; |
||
| 71 | |||
| 72 | options.previewParserPath = localize(options.previewParserPath); |
||
| 73 | options.previewTemplatePath = localize(options.previewTemplatePath); |
||
| 74 | |||
| 75 | // apply the computed path to ~/ |
||
| 76 | function localize(data, inText) { |
||
| 77 | if (inText) { |
||
| 78 | return data.replace(/("|')~\//g, "$1"+options.root); |
||
| 79 | } |
||
| 80 | return data.replace(/^~\//, options.root); |
||
| 81 | } |
||
| 82 | |||
| 83 | // init and build editor |
||
| 84 | function init() { |
||
| 85 | id = ''; nameSpace = ''; |
||
| 86 | if (options.id) { |
||
| 87 | id = 'id="'+options.id+'"'; |
||
| 88 | } else if ($$.attr("id")) { |
||
| 89 | id = 'id="markItUp'+($$.attr("id").substr(0, 1).toUpperCase())+($$.attr("id").substr(1))+'"'; |
||
| 90 | |||
| 91 | } |
||
| 92 | if (options.nameSpace) { |
||
| 93 | nameSpace = 'class="'+options.nameSpace+'"'; |
||
| 94 | } |
||
| 95 | $$.wrap('<div '+nameSpace+'></div>'); |
||
| 96 | $$.wrap('<div '+id+' class="markItUp"></div>'); |
||
| 97 | $$.wrap('<div class="markItUpContainer"></div>'); |
||
| 98 | $$.addClass("markItUpEditor"); |
||
| 99 | |||
| 100 | // add the header before the textarea |
||
| 101 | header = $('<div class="markItUpHeader"></div>').insertBefore($$); |
||
| 102 | $(dropMenus(options.markupSet)).appendTo(header); |
||
| 103 | |||
| 104 | // add the footer after the textarea |
||
| 105 | footer = $('<div class="markItUpFooter"></div>').insertAfter($$); |
||
| 106 | |||
| 107 | // add the resize handle after textarea |
||
| 108 | if (options.resizeHandle === true) { |
||
| 109 | resizeHandle = $('<div class="markItUpResizeHandle"></div>') |
||
| 110 | .insertAfter($$) |
||
| 111 | .bind("mousedown", function(e) { |
||
| 112 | var h = $$.height(), y = e.clientY, mouseMove, mouseUp; |
||
| 113 | mouseMove = function(e) { |
||
| 114 | $$.css("height", Math.max(20, e.clientY+h-y)+"px"); |
||
| 115 | return false; |
||
| 116 | }; |
||
| 117 | mouseUp = function(e) { |
||
| 118 | $("html").unbind("mousemove", mouseMove).unbind("mouseup", mouseUp); |
||
| 119 | return false; |
||
| 120 | }; |
||
| 121 | $("html").bind("mousemove", mouseMove).bind("mouseup", mouseUp); |
||
| 122 | }); |
||
| 123 | footer.append(resizeHandle); |
||
| 124 | } |
||
| 125 | |||
| 126 | // listen key events |
||
| 127 | $$.keydown(keyPressed).keyup(keyPressed); |
||
| 128 | |||
| 129 | // bind an event to catch external calls |
||
| 130 | $$.bind("insertion", function(e, settings) { |
||
| 131 | if (settings.target !== false) { |
||
| 132 | get(); |
||
| 133 | } |
||
| 134 | if (textarea === $.markItUp.focused) { |
||
| 135 | markup(settings); |
||
| 136 | } |
||
| 137 | }); |
||
| 138 | |||
| 139 | // remember the last focus |
||
| 140 | $$.focus(function() { |
||
| 141 | $.markItUp.focused = this; |
||
| 142 | }); |
||
| 143 | } |
||
| 144 | |||
| 145 | // recursively build header with dropMenus from markupset |
||
| 146 | function dropMenus(markupSet) { |
||
| 147 | var ul = $('<ul></ul>'), i = 0; |
||
| 148 | $('li:hover > ul', ul).css('display', 'block'); |
||
| 149 | $.each(markupSet, function() { |
||
| 150 | var button = this, t = '', title, li, j; |
||
| 151 | title = (button.key) ? (button.name||'')+' [Ctrl+'+button.key+']' : (button.name||''); |
||
| 152 | key = (button.key) ? 'accesskey="'+button.key+'"' : ''; |
||
| 153 | if (button.separator) { |
||
| 154 | li = $('<li class="markItUpSeparator">'+(button.separator||'')+'</li>').appendTo(ul); |
||
| 155 | } else { |
||
| 156 | i++; |
||
| 157 | for (j = levels.length -1; j >= 0; j--) { |
||
| 158 | t += levels[j]+"-"; |
||
| 159 | } |
||
| 160 | li = $('<li class="markItUpButton markItUpButton'+t+(i)+' '+(button.className||'')+'"><a href="" '+key+' title="'+title+'">'+(button.name||'')+'</a></li>') |
||
| 161 | .bind("contextmenu", function() { // prevent contextmenu on mac and allow ctrl+click |
||
| 162 | return false; |
||
| 163 | }).click(function() { |
||
| 164 | return false; |
||
| 165 | }).bind("focusin", function(){ |
||
| 166 | $$.focus(); |
||
| 167 | }).mousedown(function() { |
||
| 168 | if (button.call) { |
||
| 169 | eval(button.call)(); |
||
| 170 | } |
||
| 171 | setTimeout(function() { markup(button) },1); |
||
| 172 | return false; |
||
| 173 | }).hover(function() { |
||
| 174 | $('> ul', this).show(); |
||
| 175 | $(document).one('click', function() { // close dropmenu if click outside |
||
| 176 | $('ul ul', header).hide(); |
||
| 177 | } |
||
| 178 | ); |
||
| 179 | }, function() { |
||
| 180 | $('> ul', this).hide(); |
||
| 181 | } |
||
| 182 | ).appendTo(ul); |
||
| 183 | if (button.dropMenu) { |
||
| 184 | levels.push(i); |
||
| 185 | $(li).addClass('markItUpDropMenu').append(dropMenus(button.dropMenu)); |
||
| 186 | } |
||
| 187 | } |
||
| 188 | }); |
||
| 189 | levels.pop(); |
||
| 190 | return ul; |
||
| 191 | } |
||
| 192 | |||
| 193 | // markItUp! markups |
||
| 194 | function magicMarkups(string) { |
||
| 195 | if (string) { |
||
| 196 | string = string.toString(); |
||
| 197 | string = string.replace(/\(\!\(([\s\S]*?)\)\!\)/g, |
||
| 198 | function(x, a) { |
||
| 199 | var b = a.split('|!|'); |
||
| 200 | if (altKey === true) { |
||
| 201 | return (b[1] !== undefined) ? b[1] : b[0]; |
||
| 202 | } else { |
||
| 203 | return (b[1] === undefined) ? "" : b[0]; |
||
| 204 | } |
||
| 205 | } |
||
| 206 | ); |
||
| 207 | // [![prompt]!], [![prompt:!:value]!] |
||
| 208 | string = string.replace(/\[\!\[([\s\S]*?)\]\!\]/g, |
||
| 209 | function(x, a) { |
||
| 210 | var b = a.split(':!:'); |
||
| 211 | if (abort === true) { |
||
| 212 | return false; |
||
| 213 | } |
||
| 214 | value = prompt(b[0], (b[1]) ? b[1] : ''); |
||
| 215 | if (value === null) { |
||
| 216 | abort = true; |
||
| 217 | } |
||
| 218 | return value; |
||
| 219 | } |
||
| 220 | ); |
||
| 221 | return string; |
||
| 222 | } |
||
| 223 | return ""; |
||
| 224 | } |
||
| 225 | |||
| 226 | // prepare action |
||
| 227 | function prepare(action) { |
||
| 228 | if ($.isFunction(action)) { |
||
| 229 | action = action(hash); |
||
| 230 | } |
||
| 231 | return magicMarkups(action); |
||
| 232 | } |
||
| 233 | |||
| 234 | // build block to insert |
||
| 235 | function build(string) { |
||
| 236 | var openWith = prepare(clicked.openWith); |
||
| 237 | var placeHolder = prepare(clicked.placeHolder); |
||
| 238 | var replaceWith = prepare(clicked.replaceWith); |
||
| 239 | var closeWith = prepare(clicked.closeWith); |
||
| 240 | if (replaceWith !== "") { |
||
| 241 | block = openWith + replaceWith + closeWith; |
||
| 242 | } else if (selection === '' && placeHolder !== '') { |
||
| 243 | block = openWith + placeHolder + closeWith; |
||
| 244 | } else { |
||
| 245 | string = string || selection; |
||
| 246 | if (string.match(/ $/)) { |
||
| 247 | block = openWith + string.replace(/ $/, '') + closeWith + ' '; |
||
| 248 | } else { |
||
| 249 | block = openWith + string + closeWith; |
||
| 250 | } |
||
| 251 | } |
||
| 252 | return { block:block, |
||
| 253 | openWith:openWith, |
||
| 254 | replaceWith:replaceWith, |
||
| 255 | placeHolder:placeHolder, |
||
| 256 | closeWith:closeWith |
||
| 257 | }; |
||
| 258 | } |
||
| 259 | |||
| 260 | // define markup to insert |
||
| 261 | function markup(button) { |
||
| 262 | var len, j, n, i; |
||
| 263 | hash = clicked = button; |
||
| 264 | get(); |
||
| 265 | |||
| 266 | $.extend(hash, { line:"", |
||
| 267 | root:options.root, |
||
| 268 | textarea:textarea, |
||
| 269 | selection:(selection||''), |
||
| 270 | caretPosition:caretPosition, |
||
| 271 | ctrlKey:ctrlKey, |
||
| 272 | shiftKey:shiftKey, |
||
| 273 | altKey:altKey |
||
| 274 | } |
||
| 275 | ); |
||
| 276 | // callbacks before insertion |
||
| 277 | prepare(options.beforeInsert); |
||
| 278 | prepare(clicked.beforeInsert); |
||
| 279 | if (ctrlKey === true && shiftKey === true) { |
||
| 280 | prepare(clicked.beforeMultiInsert); |
||
| 281 | } |
||
| 282 | $.extend(hash, { line:1 }); |
||
| 283 | |||
| 284 | if (ctrlKey === true && shiftKey === true) { |
||
| 285 | lines = selection.split(/\r?\n/); |
||
| 286 | for (j = 0, n = lines.length, i = 0; i < n; i++) { |
||
| 287 | if ($.trim(lines[i]) !== '') { |
||
| 288 | $.extend(hash, { line:++j, selection:lines[i] } ); |
||
| 289 | lines[i] = build(lines[i]).block; |
||
| 290 | } else { |
||
| 291 | lines[i] = ""; |
||
| 292 | } |
||
| 293 | } |
||
| 294 | string = { block:lines.join('\n')}; |
||
| 295 | start = caretPosition; |
||
| 296 | len = string.block.length + ((false) ? n-1 : 0); |
||
| 297 | } else if (ctrlKey === true) { |
||
| 298 | string = build(selection); |
||
| 299 | start = caretPosition + string.openWith.length; |
||
| 300 | len = string.block.length - string.openWith.length - string.closeWith.length; |
||
| 301 | len = len - (string.block.match(/ $/) ? 1 : 0); |
||
| 302 | len -= fixIeBug(string.block); |
||
| 303 | } else if (shiftKey === true) { |
||
| 304 | string = build(selection); |
||
| 305 | start = caretPosition; |
||
| 306 | len = string.block.length; |
||
| 307 | len -= fixIeBug(string.block); |
||
| 308 | } else { |
||
| 309 | string = build(selection); |
||
| 310 | start = caretPosition + string.block.length ; |
||
| 311 | len = 0; |
||
| 312 | start -= fixIeBug(string.block); |
||
| 313 | } |
||
| 314 | if ((selection === '' && string.replaceWith === '')) { |
||
| 315 | caretOffset += fixOperaBug(string.block); |
||
| 316 | |||
| 317 | start = caretPosition + string.openWith.length; |
||
| 318 | len = string.block.length - string.openWith.length - string.closeWith.length; |
||
| 319 | |||
| 320 | caretOffset = $$.val().substring(caretPosition, $$.val().length).length; |
||
| 321 | caretOffset -= fixOperaBug($$.val().substring(0, caretPosition)); |
||
| 322 | } |
||
| 323 | $.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } ); |
||
| 324 | |||
| 325 | if (string.block !== selection && abort === false) { |
||
| 326 | insert(string.block); |
||
| 327 | set(start, len); |
||
| 328 | } else { |
||
| 329 | caretOffset = -1; |
||
| 330 | } |
||
| 331 | get(); |
||
| 332 | |||
| 333 | $.extend(hash, { line:'', selection:selection }); |
||
| 334 | |||
| 335 | // callbacks after insertion |
||
| 336 | if (ctrlKey === true && shiftKey === true) { |
||
| 337 | prepare(clicked.afterMultiInsert); |
||
| 338 | } |
||
| 339 | prepare(clicked.afterInsert); |
||
| 340 | prepare(options.afterInsert); |
||
| 341 | |||
| 342 | // refresh preview if opened |
||
| 343 | if (previewWindow && options.previewAutoRefresh) { |
||
| 344 | refreshPreview(); |
||
| 345 | } |
||
| 346 | |||
| 347 | // reinit keyevent |
||
| 348 | shiftKey = altKey = ctrlKey = abort = false; |
||
| 349 | } |
||
| 350 | |||
| 351 | // Substract linefeed in Opera |
||
| 352 | function fixOperaBug(string) { |
||
| 353 | if (false) { |
||
| 354 | return string.length - string.replace(/\n*/g, '').length; |
||
| 355 | } |
||
| 356 | return 0; |
||
| 357 | } |
||
| 358 | // Substract linefeed in IE |
||
| 359 | function fixIeBug(string) { |
||
| 360 | if (false) { |
||
| 361 | return string.length - string.replace(/\r/g, '').length; |
||
| 362 | } |
||
| 363 | return 0; |
||
| 364 | } |
||
| 365 | |||
| 366 | // add markup |
||
| 367 | function insert(block) { |
||
| 368 | if (document.selection) { |
||
| 369 | var newSelection = document.selection.createRange(); |
||
| 370 | newSelection.text = block; |
||
| 371 | } else { |
||
| 372 | textarea.value = textarea.value.substring(0, caretPosition) + block + textarea.value.substring(caretPosition + selection.length, textarea.value.length); |
||
| 373 | } |
||
| 374 | } |
||
| 375 | |||
| 376 | // set a selection |
||
| 377 | function set(start, len) { |
||
| 378 | if (textarea.createTextRange){ |
||
| 379 | // quick fix to make it work on Opera 9.5 |
||
| 380 | if (len == 0) { |
||
| 381 | return false; |
||
| 382 | } |
||
| 383 | range = textarea.createTextRange(); |
||
| 384 | range.collapse(true); |
||
| 385 | range.moveStart('character', start); |
||
| 386 | range.moveEnd('character', len); |
||
| 387 | range.select(); |
||
| 388 | } else if (textarea.setSelectionRange ){ |
||
| 389 | textarea.setSelectionRange(start, start + len); |
||
| 390 | } |
||
| 391 | textarea.scrollTop = scrollPosition; |
||
| 392 | textarea.focus(); |
||
| 393 | } |
||
| 394 | |||
| 395 | // get the selection |
||
| 396 | function get() { |
||
| 397 | textarea.focus(); |
||
| 398 | |||
| 399 | scrollPosition = textarea.scrollTop; |
||
| 400 | if (document.selection) { |
||
| 401 | selection = document.selection; |
||
| 402 | if (false) { // ie |
||
| 403 | var range = selection.createRange(); |
||
| 404 | var stored_range = range.duplicate(); |
||
| 405 | stored_range.moveToElementText(textarea); |
||
| 406 | stored_range.setEndPoint('EndToEnd', range); |
||
| 407 | var s = stored_range.text.length - range.text.length; |
||
| 408 | |||
| 409 | caretPosition = s - (textarea.value.substr(0, s).length - textarea.value.substr(0, s).replace(/\r/g, '').length); |
||
| 410 | selection = range.text; |
||
| 411 | } else { // opera |
||
| 412 | caretPosition = textarea.selectionStart; |
||
| 413 | } |
||
| 414 | } else { // gecko & webkit |
||
| 415 | caretPosition = textarea.selectionStart; |
||
| 416 | selection = textarea.value.substring(caretPosition, textarea.selectionEnd); |
||
| 417 | } |
||
| 418 | return selection; |
||
| 419 | } |
||
| 420 | |||
| 421 | // open preview window |
||
| 422 | function preview() { |
||
| 423 | if (!previewWindow || previewWindow.closed) { |
||
| 424 | if (options.previewInWindow) { |
||
| 425 | previewWindow = window.open('', 'preview', options.previewInWindow); |
||
| 426 | $(window).unload(function() { |
||
| 427 | previewWindow.close(); |
||
| 428 | }); |
||
| 429 | } else { |
||
| 430 | iFrame = $('<iframe class="markItUpPreviewFrame"></iframe>'); |
||
| 431 | if (options.previewPosition == 'after') { |
||
| 432 | iFrame.insertAfter(footer); |
||
| 433 | } else { |
||
| 434 | iFrame.insertBefore(header); |
||
| 435 | } |
||
| 436 | previewWindow = iFrame[iFrame.length - 1].contentWindow || frame[iFrame.length - 1]; |
||
| 437 | } |
||
| 438 | } else if (altKey === true) { |
||
| 439 | if (iFrame) { |
||
| 440 | iFrame.remove(); |
||
| 441 | } else { |
||
| 442 | previewWindow.close(); |
||
| 443 | } |
||
| 444 | previewWindow = iFrame = false; |
||
| 445 | } |
||
| 446 | if (!options.previewAutoRefresh) { |
||
| 447 | refreshPreview(); |
||
| 448 | } |
||
| 449 | if (options.previewInWindow) { |
||
| 450 | previewWindow.focus(); |
||
| 451 | } |
||
| 452 | } |
||
| 453 | |||
| 454 | // refresh Preview window |
||
| 455 | function refreshPreview() { |
||
| 456 | renderPreview(); |
||
| 457 | } |
||
| 458 | |||
| 459 | function renderPreview() { |
||
| 460 | var phtml; |
||
| 461 | if (options.previewParserPath !== '') { |
||
| 462 | $.ajax({ |
||
| 463 | type: 'POST', |
||
| 464 | dataType: 'text', |
||
| 465 | global: false, |
||
| 466 | url: options.previewParserPath, |
||
| 467 | data: options.previewParserVar+'='+encodeURIComponent($$.val()), |
||
| 468 | success: function(data) { |
||
| 469 | writeInPreview( localize(data, 1) ); |
||
| 470 | } |
||
| 471 | }); |
||
| 472 | } else { |
||
| 473 | if (!template) { |
||
| 474 | $.ajax({ |
||
| 475 | url: options.previewTemplatePath, |
||
| 476 | dataType: 'text', |
||
| 477 | global: false, |
||
| 478 | success: function(data) { |
||
| 479 | writeInPreview( localize(data, 1).replace(/<!-- content -->/g, $$.val()) ); |
||
| 480 | } |
||
| 481 | }); |
||
| 482 | } |
||
| 483 | } |
||
| 484 | return false; |
||
| 485 | } |
||
| 486 | |||
| 487 | function writeInPreview(data) { |
||
| 488 | if (previewWindow.document) { |
||
| 489 | try { |
||
| 490 | sp = previewWindow.document.documentElement.scrollTop |
||
| 491 | } catch(e) { |
||
| 492 | sp = 0; |
||
| 493 | } |
||
| 494 | previewWindow.document.open(); |
||
| 495 | previewWindow.document.write(data); |
||
| 496 | previewWindow.document.close(); |
||
| 497 | previewWindow.document.documentElement.scrollTop = sp; |
||
| 498 | } |
||
| 499 | } |
||
| 500 | |||
| 501 | // set keys pressed |
||
| 502 | function keyPressed(e) { |
||
| 503 | shiftKey = e.shiftKey; |
||
| 504 | altKey = e.altKey; |
||
| 505 | ctrlKey = (!(e.altKey && e.ctrlKey)) ? e.ctrlKey : false; |
||
| 506 | |||
| 507 | if (e.type === 'keydown') { |
||
| 508 | if (ctrlKey === true) { |
||
| 509 | li = $("a[accesskey="+String.fromCharCode(e.keyCode)+"]", header).parent('li'); |
||
| 510 | if (li.length !== 0) { |
||
| 511 | ctrlKey = false; |
||
| 512 | setTimeout(function() { |
||
| 513 | li.triggerHandler('mousedown'); |
||
| 514 | },1); |
||
| 515 | return false; |
||
| 516 | } |
||
| 517 | } |
||
| 518 | if (e.keyCode === 13 || e.keyCode === 10) { // Enter key |
||
| 519 | if (ctrlKey === true) { // Enter + Ctrl |
||
| 520 | ctrlKey = false; |
||
| 521 | markup(options.onCtrlEnter); |
||
| 522 | return options.onCtrlEnter.keepDefault; |
||
| 523 | } else if (shiftKey === true) { // Enter + Shift |
||
| 524 | shiftKey = false; |
||
| 525 | markup(options.onShiftEnter); |
||
| 526 | return options.onShiftEnter.keepDefault; |
||
| 527 | } else { // only Enter |
||
| 528 | markup(options.onEnter); |
||
| 529 | return options.onEnter.keepDefault; |
||
| 530 | } |
||
| 531 | } |
||
| 532 | if (e.keyCode === 9) { // Tab key |
||
| 533 | if (shiftKey == true || ctrlKey == true || altKey == true) { |
||
| 534 | return false; |
||
| 535 | } |
||
| 536 | if (caretOffset !== -1) { |
||
| 537 | get(); |
||
| 538 | caretOffset = $$.val().length - caretOffset; |
||
| 539 | set(caretOffset, 0); |
||
| 540 | caretOffset = -1; |
||
| 541 | return false; |
||
| 542 | } else { |
||
| 543 | markup(options.onTab); |
||
| 544 | return options.onTab.keepDefault; |
||
| 545 | } |
||
| 546 | } |
||
| 547 | } |
||
| 548 | } |
||
| 549 | |||
| 550 | init(); |
||
| 551 | }); |
||
| 552 | }; |
||
| 553 | |||
| 575 |